import { HttpException, HttpStatus, Injectable } from "@nestjs/common";
import { CreateContentDto } from './dto/create-content.dto';
import { UpdateContentDto } from './dto/update-content.dto';
import { Content } from "./entities/content.entity";
import { DataSource, Repository } from "typeorm";
import { InjectRepository } from "@nestjs/typeorm";
import { Tag } from "../tags/entities/tag.entity";
import { FindListDto } from "./dto/find-list-content.dto";

export interface ContentTreeNode extends Content {
  children: ContentTreeNode[]
}

@Injectable()
export class ContentService {
  constructor(
    @InjectRepository(Content)
    private readonly contentRepository: Repository<Content>,
    @InjectRepository(Tag)
    private readonly tagRepository: Repository<Tag>,
    private readonly connection: DataSource,
  ) {
  }

  async create(createContentDto: CreateContentDto) {
    const {parentId} = createContentDto
    const tags = await Promise.all(createContentDto.tags.map((label) => this.preloadTag(label)));
    // 获取当前统一级别的最大排序值
    const maxSortOrderQuery = this.contentRepository
      .createQueryBuilder('content')
      .select('MAX(content.sortOrder)','max')
    if (parentId === null) {
      createContentDto.type = "category"
      maxSortOrderQuery.where('content.parentId IS NULL')
    } else {
      maxSortOrderQuery.where('content.parentId = :parentId', {parentId})
    }

    const maxSortOrder = await maxSortOrderQuery.getRawOne().then(res => res.max || 0)

    createContentDto.sortOrder = maxSortOrder + 1

    const newContent = this.contentRepository.create({
      ...createContentDto,
      tags,
    })
    return this.contentRepository.save(newContent)
  }

  findTopLevel() {
    return this.contentRepository.find({
      where: {parentId: null},
      order: {sortOrder: 'ASC'}
    })
  }

  async findTree(findListDto: FindListDto) {
    const {topLevelId} = findListDto
    const contents = await this.contentRepository.find({
      relations: ['tags'],
      where: {topLevelId},
      order: {sortOrder: 'ASC'}
    })
    return this.buildTree(contents, topLevelId);
  }

  async findOne(id: number) {
    const existingContent = await this.contentRepository.findOneBy({id});
    if (!existingContent) {
      throw new Error('Content not found');
    }
    return existingContent;
  }

  async update(id: number, updateContentDto: UpdateContentDto) {
    const tags = updateContentDto.tags && (await Promise.all(updateContentDto.tags.map((tag) => this.preloadTag(tag))));
    const content = await this.contentRepository.preload({
      id,
      tags,
      ...updateContentDto
    });
    if (!content) throw new HttpException(`未找到内容 #${id}`, HttpStatus.NOT_FOUND);
    return this.contentRepository.save(content);
  }

  async remove(id: number) {
    const queryRunner = this.connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 删除指定 id 的内容
      await queryRunner.manager.delete(Content, { id });

      // 删除 parentId 为指定 id 的所有子内容
      const contentsToDelete = await queryRunner.manager.getRepository(Content).find({ where: { parentId: id } });
      for (const content of contentsToDelete) {
        await this.removeContentWithChildren(queryRunner, content.id);
      }

      await queryRunner.commitTransaction();
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
    } finally {
      await queryRunner.release();
    }
  }

  private async preloadTag(tag: Tag): Promise<Tag> {
    const existingTag = await this.tagRepository.findOne({ where: { id: tag.id } });
    if (existingTag) return existingTag;
    return this.tagRepository.create({ ...tag });
  }

  private buildTree(contents: Content[], topLevelId: Content['topLevelId']): ContentTreeNode[] {
    const map = new Map<number, ContentTreeNode>()
    const roots: ContentTreeNode[] = []

    contents.forEach(content => {
      map.set(content.id, {...content, children: []})
    })

    contents.forEach(content => {
      const mappedContent = map.get(content.id)
      if (content.parentId === topLevelId) {
        roots.push(mappedContent)
      } else {
        const parentContent = map.get(content.parentId)
        if (parentContent) {
          parentContent.children.push(mappedContent)
        }
      }
    })
    console.log(roots);
    return roots
  }

  private async removeContentWithChildren(queryRunner: any, id: number) {
    // 递归删除子内容
    const children = await queryRunner.manager.getRepository(Content).find({ where: { parentId: id } });
    for (const child of children) {
      await this.removeContentWithChildren(queryRunner, child.id);
    }

    // 删除当前内容
    await queryRunner.manager.delete(Content, { id });
  }
}
